﻿using System;
using System.Collections.Generic;
using System.Text;

namespace Teal.Compiler {

    /// <summary>
    /// 表示一个成员（如方法、字段、类型、包等）引用。
    /// </summary>
    public abstract partial class MemberReference {

        /// <summary>
        /// 查询当前包内指定全名对应的成员。
        /// </summary>
        /// <param name="fullName">要查询的类型全名。</param>
        /// <returns></returns>
        public MemberReference queryMember(string fullName) {
            MemberReference current = this;
            int index = 0;
            queryMember(memberType == MemberType.@namespace ? this : containerModule, fullName, ref current, ref index);
            return current;
        }

        private static void queryMember(MemberReference root, string fullName, ref MemberReference current, ref int index) {

            // 已经读取完毕。
            if (index >= fullName.Length) {
                return;
            }

            switch (fullName[index]) {

                // 开始读取泛型参数。
                case '<': {
                        index++;
                        bool hasArguments = true;
                        List<TypeReference> types = ListObjectPool<TypeReference>.alloc();
                    parseNextType:
                        MemberReference member = root;
                        queryMember(root, fullName, ref member, ref index);
                        TypeReference type = member as TypeReference;
                        if (type == null) {
                            hasArguments = false;
                        }
                        types.Add(type);
                        if (index < fullName.Length && fullName[index] == ',') {
                            index++;
                            goto parseNextType;
                        }

                        var arr = types.ToArray();
                        ListObjectPool<TypeReference>.free(types);

                        // 找出指定泛型参数个数的成员。
                        for (var c = current; c != null; c = c.next) {
                            if (c.matchGenericArgumentCount(arr.Length)) {

                                if (hasArguments) {
                                    var gt = c as GenericTypeDefinitionReference;
                                    if (gt != null) {
                                        current = gt.makeGenericType(arr);
                                        return;
                                    }

                                    var gm = c as GenericMethodDefinitionReference;
                                    if (gm != null) {
                                        current = gm.makeGenericMethod(arr);
                                        return;
                                    }

                                }

                                current = c;
                                return;
                            }
                        }

                        current = null;
                        return;
                    }

                // 开始读取函数参数。
                case '(': {
                        index++;
                        List<TypeReference> types = ListObjectPool<TypeReference>.alloc();
                    parseNextType:
                        MemberReference member = root;
                        queryMember(root, fullName, ref member, ref index);
                        TypeReference type = member as TypeReference;
                        types.Add(type);
                        if (index < fullName.Length && fullName[index] == ',') {
                            index++;
                            goto parseNextType;
                        }

                        var arr = types.ToArray();
                        ListObjectPool<TypeReference>.free(types);

                        // 找出指定泛型参数个数的成员。
                        for (var c = current; c != null; c = c.next) {
                            var m = c as MethodReference;
                            if (m == null) {
                                current = m;
                                return;
                            }

                            bool notMatch = false;
                            for (var p = 0; p < arr.Length; p++) {
                                if (p >= m.parameters.Length || m.parameters[p].type != arr[p]) {
                                    notMatch = true;
                                    break;
                                }
                            }

                            if (!notMatch) {
                                current = c;
                                return;
                            }

                        }

                        current = null;
                        return;
                    }

                // 开始读取关闭标记。
                case '.':
                case ')':
                case '>':
                case ' ':
                    index++;
                    queryMember(root, fullName, ref current, ref index);
                    return;

                // 开始读取子成员。
                default: {

                        // 开始读取子类型名，直到 . 或 < 或 (
                        int start = index;
                        while (index < fullName.Length && fullName[index] != '.' && fullName[index] != '<' && fullName[index] != '>' && fullName[index] != '(' && fullName[index] != ')' && fullName[index] != ',' && fullName[index] != ' ') {
                            index++;
                        }

                        string memberName = fullName.Substring(start, index - start);
                        switch (memberName) {
                            case "int":
                                current = PredefinedTypes.System_Int32;
                                return;
                            case "var":
                                current = PredefinedTypes.@var;
                                return;
                            case "void":
                                current = PredefinedTypes.@void;
                                return;
                            case "bool":
                                current = PredefinedTypes.System_Bool;
                                return;
                            case "object":
                                current = PredefinedTypes.System_Object;
                                return;
                            case "string":
                                current = PredefinedTypes.System_String;
                                return;
                            case "short":
                                current = PredefinedTypes.System_Int16;
                                return;
                            case "char":
                                current = PredefinedTypes.System_Char;
                                return;
                            case "byte":
                                current = PredefinedTypes.System_Byte;
                                return;
                            case "long":
                                current = PredefinedTypes.System_Int64;
                                return;
                            case "uint":
                                current = PredefinedTypes.System_UInt32;
                                return;
                            case "ushort":
                                current = PredefinedTypes.System_UIint16;
                                return;
                            case "ulong":
                                current = PredefinedTypes.System_UInt64;
                                return;
                            case "float":
                                current = PredefinedTypes.System_Float32;
                                return;
                            case "double":
                                current = PredefinedTypes.System_Float64;
                                return;
                            default:

                                var t = current as NamespaceReference;
                                if (t == null) {
                                    current = null;
                                    return;
                                }

                                current = t.getMember(memberName);
                                if (current == null) {
                                    return;
                                }
                                queryMember(root, fullName, ref current, ref index);
                                return;
                        }
                    }
            }

        }
    }

}
